package com.weaver.drools.common.shiro.service.impl;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.Authenticator;
import org.apache.shiro.authc.LogoutAware;
import org.apache.shiro.session.Session;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.shiro.subject.support.DefaultSubjectContext;
import org.apache.shiro.web.filter.mgt.DefaultFilterChainManager;
import org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.AbstractShiroFilter;
import org.crazycake.shiro.RedisSessionDAO;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import com.weaver.drools.business.sys.permission.service.ISysPermissionService;
import com.weaver.drools.common.entity.SysPermissionInit;
import com.weaver.drools.common.entity.SysUser;
import com.weaver.drools.common.redis.utils.RedisConstant;
import com.weaver.drools.common.shiro.service.ShiroService;
import com.weaver.drools.common.shiro.service.SysPermissionInitService;
import java.util.*;
import javax.annotation.Resource;
/**
*
*  @application name：
*  @author: zhouxinlei
*  @time：2018年10月16日
*  @version：ver 1.1
*/
@Service
public class ShiroServiceImpl implements ShiroService{
	
	@Resource
    private  RedisSessionDAO redisSessionDAO;
	
	@Resource
    private RedisTemplate<String, String> stringRedisTemplate;
    
    private static String prefix = RedisConstant.shiro_redis_session+":";
    
	@Resource
	private ISysPermissionService permissionService;
	
	@Resource
	private SysPermissionInitService permissionInitService;
	
	
	@Override
	public Map<String, String> loadFilterChainDefinitions() {
		Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
		List<SysPermissionInit> sysPermissionInits = permissionInitService.findSysPermissionInitList();
		//公共资源配置
		for (SysPermissionInit sysPermissionInit : sysPermissionInits) {
			filterChainDefinitionMap.put(sysPermissionInit.getPermissionInitUrl(), sysPermissionInit.getPermissionInitCode());
		}
        //拦截所有请求
        filterChainDefinitionMap.put("/**", "authc");
		return filterChainDefinitionMap;
	}

	@Override
	public void updatePermission(ShiroFilterFactoryBean shiroFilterFactoryBean) {
		synchronized (this) {    
			AbstractShiroFilter shiroFilter;
            try {
                shiroFilter = (AbstractShiroFilter) shiroFilterFactoryBean.getObject();
            } catch (Exception e) {
                throw new RuntimeException("get ShiroFilter from shiroFilterFactoryBean error!");
            }
            PathMatchingFilterChainResolver filterChainResolver = (PathMatchingFilterChainResolver) shiroFilter.getFilterChainResolver();
            DefaultFilterChainManager manager = (DefaultFilterChainManager) filterChainResolver.getFilterChainManager();
            // 清空老的权限控制
            manager.getFilterChains().clear();
            shiroFilterFactoryBean.getFilterChainDefinitionMap().clear();
            shiroFilterFactoryBean.setFilterChainDefinitionMap(loadFilterChainDefinitions());
            // 重新构建生成
            Map<String, String> chains = shiroFilterFactoryBean.getFilterChainDefinitionMap();
            for (Map.Entry<String, String> entry : chains.entrySet()) {
                String url = entry.getKey();
                String chainDefinition = entry.getValue().trim()
                        .replace(" ", "");
                manager.createChain(url, chainDefinition);
            }
            updateSession();
		}
    }
	 /**
     * 获取指定用户名的Session
     * @param username
     * @return
     */
    public Session getSessionByUsername(String username){
        Collection<Session> sessions = redisSessionDAO.getActiveSessions();
        SysUser user;
        Object attribute;
        for(Session session : sessions){
            attribute = session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY);
            if (attribute == null) {
                continue;
            }
            user = (SysUser) ((SimplePrincipalCollection) attribute).getPrimaryPrincipal();
            if (user == null) {
                continue;
            }
            if (Objects.equals(user.getUsername(), username)) {
                return session;
            }
        }
        return null;
    }
    /**
     * 	删除用户缓存信息
     * @param username 用户名
     * @param isRemoveSession 是否删除session，删除后用户需重新登录
     */
    public void updateSession(){
    	SysUser loginUser = (SysUser) SecurityUtils.getSubject().getPrincipal();
        Session session = getSessionByUsername(loginUser.getUsername());
        if (session == null) {
            return;
        }

        Object attribute = session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY);
        if (attribute == null) {
            return;
        }

        SysUser user = (SysUser) ((SimplePrincipalCollection) attribute).getPrimaryPrincipal();
        if (loginUser.getUsername().equals(user.getUsername())) {
        	//更新shiro session缓存
        	Set<String> keys = stringRedisTemplate.keys(prefix + "*");
        	stringRedisTemplate.delete(keys);
            redisSessionDAO.update(session);
            //更新登陆者缓存
            String key = RedisConstant.SYS_USER+"::"+user.getUsername();
            stringRedisTemplate.delete(key);
        }
        DefaultWebSecurityManager securityManager = (DefaultWebSecurityManager) SecurityUtils.getSecurityManager();
        Authenticator authc = securityManager.getAuthenticator();
        //删除cache，在访问受限接口时会重新授权
        ((LogoutAware) authc).onLogout((SimplePrincipalCollection) attribute);
    }
}
